JavaScript30第六天要學習的是利用 fetch 串接 API,並利用新的事件 input 抓取使用者輸入的文字,再使用 正則表達式 篩選出 Data 中哪些地區有符合輸入字串
Github 檔案位置:06 - Type Ahead
網頁一開始的樣子如下
可以先去看看 最後的成品 如下
將程式的要求拆分步驟後,我們需要做的事情如下
應用前幾天學到的東西,不一樣的是這次用了 input 事件 偵測輸入
function displayMatches() {
  console.log(this.value) // 確認什麼時候會觸發事件
}
const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');
searchInput.addEventListener('input', displayMatches);

在這裡我們利用了 fetch 去串接 API,再利用 json() 將 JSON 檔解析為 JS 物件,並利用 解構賦值 將 Data 傳至我們的 List 中
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
const cities = [];
fetch(endpoint)
 .then(item => item.json())
 .then(data => cities.push(...data));
console.log(cities);

在這裡我們用到了之前剛學的 filter,不同的是這次用了 正則表達式 和 match 做搭配
new RegExp 會幫助我們建立一個正則表達式的物件,其中 gi 是參數,g 的意思是全域搜尋,i則是不區分大小寫
match() 會依造我們設立的規則去搜尋 Data,如果存在就會回傳 true
function findMatches(wordToMatch, cities) {
  return cities.filter(place => {
    // g:全域搜尋 
    // i:不分大小寫
    const regex = new RegExp(wordToMatch, 'gi');
    return place.city.match(regex) || place.state.match(regex);
  })
}
在這裡可以利用偷懶的方式直接使用 toLocaleString() 函數
function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  return (x * 1).toLocaleString();
}
然後我們要學習的是正則表達式的應用
成品如下,replace 做的事情是將正則表達式找到的地方替換為 ,
function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  // return (x * 1).toLocaleString();
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
統整完資訊之後,我們將所有資訊包進 HTML 語法的字串中,並以 suggestions.innerHTML 渲染進網頁中
const html = matchArray.map(place => { 
    const regex = new RegExp(this.value, 'gi'); 
    const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    return `
      <li>
        <span class="name">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCommas(place.population)}</span>
      </li>
    `;
    }).join(''); 
    suggestions.innerHTML = html; 
}
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
const cities = [];
fetch(endpoint)
 .then(item => item.json())
 .then(data => cities.push(...data));
console.log(cities);
function findMatches(wordToMatch, cities) {
  return cities.filter(place => {
    // g:全域搜尋 
    // i:不分大小寫
    const regex = new RegExp(wordToMatch, 'gi');
    return place.city.match(regex) || place.state.match(regex);
  })
}
function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  // return (x * 1).toLocaleString();
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
function displayMatches() {
  //console.log(this.value) // 確認什麼時候會觸發事件
  const matchArray = findMatches(this.value, cities);
  //console.log(matchArray); // 確認正則表達式結果正確
  const html = matchArray.map(place => { 
    const regex = new RegExp(this.value, 'gi'); 
    const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    return `
      <li>
        <span class="name">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCommas(place.population)}</span>
      </li>
    `;
  }).join(''); 
  suggestions.innerHTML = html; 
}
const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');
searchInput.addEventListener('input', displayMatches);

以上是第六天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽Day 6:Type Ahead
Ajax Type Ahead with fetch() - #JavaScript30 6/30
MDN Web Docs